use std::str::FromStr;

use chrono::Local;

use crate::AppState;
use chat_core::{error::AppError, CreateMessages, ListMessages, Messages, PageInstanceVO};

use super::ChatFile;

#[allow(dead_code)]
impl AppState {
    pub async fn create_messages(
        &self,
        chat_id: i64,
        sender_id: i64,
        create_message: &CreateMessages,
        username: &str,
    ) -> Result<Messages, AppError> {
        let base_dir = &self.config.server.base_dir;
        if create_message.content.is_empty() {
            return Err(AppError::CreateMessagesError(
                "content cannot be empty".to_string(),
            ));
        }
        for s in &create_message.files {
            let file = ChatFile::from_str(s)?;
            let path = file.path(base_dir);
            if !path.exists() {
                return Err(AppError::CreateMessagesError(format!(
                    "File {}  does not exist",
                    s
                )));
            };
        }
        let message: Messages = sqlx::query_as(
            r#"INSERT INTO messages (
            chat_id,
            sender_id,
            content,
            files,
            updated_name,
            created_name,
            created_date,
            updated_date
            ) VALUES ($1, $2, $3, $4,$5, $6, $7, $8)
            RETURNING
            id,
            chat_id,
            sender_id,
            content,
            files,
            updated_name,
            created_name,
            created_date,
            updated_date
            "#,
        )
        .bind(chat_id)
        .bind(sender_id)
        .bind(&create_message.content)
        .bind(&create_message.files)
        .bind(username)
        .bind(username)
        .bind(Local::now().naive_local())
        .bind(Local::now().naive_local())
        .fetch_one(&self.pool)
        .await?;
        Ok(message)
    }
    pub async fn fetch_message_by_id(&self, id: i64) -> Result<Messages, AppError> {
        let message = sqlx::query_as(
            r#"SELECT * FROM messages WHERE id = $1
        "#,
        )
        .bind(id)
        .fetch_one(&self.pool)
        .await?;
        Ok(message)
    }

    pub async fn del_message_by_chat_id(&self, chat_id: i64) -> Result<(), AppError> {
        sqlx::query("DELETE FROM messages WHERE chat_id = $1")
            .bind(chat_id)
            .execute(&self.pool)
            .await?;
        Ok(())
    }

    pub async fn list_messages(
        &self,
        chat_id: i64,
        list_messages: &ListMessages,
    ) -> Result<PageInstanceVO<Messages>, AppError> {
        if list_messages.page_size <= 0 {
            return Err(AppError::PageSizeError(
                "page_size must be greater than 0".to_string(),
            ));
        }
        if list_messages.page_index <= 0 {
            return Err(AppError::PageIndexError(
                "page_index must be greater than 0".to_string(),
            ));
        }

        let count: (i64,) = sqlx::query_as(
            r#"
            SELECT count(*) FROM messages WHERE chat_id = $1
                      "#,
        )
        .bind(chat_id)
        .fetch_one(&self.pool)
        .await?;
        if count.0 == 0 {
            return Ok(PageInstanceVO::empty());
        }
        let messages = sqlx::query_as(
            r#"SELECT * FROM messages WHERE chat_id = $1
                          ORDER BY created_date DESC
                          LIMIT $2
                          OFFSET $3
                          "#,
        )
        .bind(chat_id)
        .bind(list_messages.page_size)
        .bind((list_messages.page_index - 1) * list_messages.page_size)
        .fetch_all(&self.pool)
        .await?;
        Ok(PageInstanceVO::new(count.0, messages))
    }
}
#[cfg(test)]
mod tests {
    use anyhow::Result;

    use super::*;

    #[tokio::test]
    async fn test_create_messages() -> Result<()> {
        let state = AppState::new_for_test().await?;
        let create_message = CreateMessages::new("hello".to_string(), vec![]);
        assert_eq!(create_message.content, "hello");
        assert!(create_message.files.is_empty());
        let username = "jinyulinlang";
        let message = state
            .create_messages(1, 1, &create_message, username)
            .await?;
        assert_eq!(message.chat_id, 1);
        assert_eq!(message.sender_id, 1);
        assert_eq!(message.content, "hello");
        assert!(message.files.is_empty());
        state.del_message_by_chat_id(message.chat_id).await?;
        Ok(())
    }
}
